package com.rpc.spi;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ExtensionLoader
 *
 * @author 春江花朝秋月夜
 * @since 2024/1/16 21:30
 */
public class ExtensionLoader {
    private Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);
    //系统默认SPI
    private static final String   SYS_DEFAULT_SPI_DIR="META/system";
    private static final String   USER_DEFINITION_SPI_DIR="META/system";

    private static String[] prefixs={SYS_DEFAULT_SPI_DIR,USER_DEFINITION_SPI_DIR};
    // bean定义信息 key: 定义的key value：具体类
    private static Map<String, Class> extensionClassCache = new ConcurrentHashMap<>();
    // bean 定义信息 key：接口 value：接口子类s
    private static Map<String, Map<String,Class>> extensionClassCaches = new ConcurrentHashMap<>();
    // 实例化的bean
    private static Map<String, Object> singletonsObject = new ConcurrentHashMap<>();

    //通过静态方法获取实例
    private static ExtensionLoader extensionLoader;

    static {
        extensionLoader = new ExtensionLoader();
    }
    //对外提供，这里是工厂模式
    public static ExtensionLoader getInstance(){
        return extensionLoader;
    }

    //获取Bean
    public  <R> R get(String name){
        //注册服务名必须唯一
        if (!singletonsObject.containsKey(name)){
            try {
                singletonsObject.put(name,extensionClassCache.get(name).newInstance());
            } catch (InstantiationException | IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
        return (R) singletonsObject.get(name);
    }
    //这个方法是通过加载用户的配置文件将指定包下面的Bean加载到Map里面，这样当这些Bean在后置工厂中实例化的时候由于继承了InitializingBean,执行相应方法来初始化Bean
    //如果想要自定义自己的序列化格式，在META-INF下编辑自己的代码
    public void loadExtension(Class clazz) throws IOException, ClassNotFoundException {
        if (clazz==null)
        {
            throw new IllegalArgumentException("参数异常，找不到相应的class");
        }
        ClassLoader classLoader=this.getClass().getClassLoader();
        Map<String,Class> classMap=new HashMap<>();//名称-对应的class
        for (String dir:prefixs)
        {
            String spiRealPath=dir+clazz.getName();
            Enumeration<URL> enumeration= classLoader.getResources(spiRealPath);
            while (enumeration.hasMoreElements())
            {
                URL url = enumeration.nextElement();
                InputStreamReader inputStreamReader=new InputStreamReader(url.openStream());
                BufferedReader bufferedReader=new BufferedReader(inputStreamReader);
                String line;
                while ((line=bufferedReader.readLine())!=null)
                {
                    String[] configArr=line.split("=");
                    String configType=configArr[0];
                    String configClassName=configArr[1];
                    Class<?> aClass = Class.forName(configClassName);
                    extensionClassCache.put(configType,aClass);//map中加入相应的bean
                    classMap.put(configType,aClass);
                    logger.info("通过SPI加载bean,type:{},class:{}",configType,configClassName);
                }
            }
        }
        extensionClassCaches.put(clazz.getName(),classMap);
    }
}
